package com.jiawa.train.generator.gen;

import com.jiawa.train.generator.util.DbUtil;
import com.jiawa.train.generator.util.Field;
import com.jiawa.train.generator.util.FreemarkerUtil;
import freemarker.template.TemplateException;
import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.io.IOException;
import java.util.*;

public class ServerGenerator {

    static boolean readOnly = false;

    static String vuePath = "[target]/src/views/main/";

    static String serverPath = "[module]/src/main/java/com/jiawa/train/[module]/";

    static String pomPath = "generate/pom.xml";

    private static String targetPlatform = "admin"; // 生成目标平台 admin/web

    public static void main(String[] args) throws Exception {

        // 解析命令行参数
        parseArguments(args);

        configureTargetPaths();

        // 根据pom.xml获取模块path
        String generatorPath = getGeneratorPathFromPom();

        if (generatorPath == null) {
            System.err.println("无法从pom.xml中获取generator配置文件路径");
            return;
        }

        // 获取模块名
        String module = extractModuleName(generatorPath);
        if (module == null) {
            System.err.println("无法提取模块名");
            return;
        }

        initializeGenerationEnvironment(module, generatorPath);

        // 读取generator-config-xxxx.xml配置文件
        Document document = new SAXReader().read(new File(generatorPath));
        TableInfo tableInfo = extractTableInfo(document);

        configureDatabaseConnection(document);

        // 获取表元数据
        TableMetadata metadata = getTableMetadata(tableInfo.tableName);

        // 生成代码
        generateCode(tableInfo, metadata, module);

    }


    /**
     * 解析命令行参数
     */
    private static void parseArguments(String[] args) {
        if (args.length > 0) {
            targetPlatform = args[0];
        }
    }

    /**
     * 根据目标平台配置路径
     */
    private static void configureTargetPaths() {
        vuePath = vuePath.replace("[target]", targetPlatform);
    }


    /**
     * 生成文件
     *
     * @param Domain
     * @param param
     * @param target ( controller/service )
     * @throws IOException
     * @throws TemplateException
     */
    private static void genFile(String Domain, Map<String, Object> param, String packageName, String target) throws IOException, TemplateException {
        FreemarkerUtil.initConfig(target + ".ftl");
        String Target = target.substring(0, 1).toUpperCase() + target.substring(1);
        String toPath = serverPath + packageName + "/";
        String fileName = toPath + Domain + Target + ".java";

        new File(toPath).mkdirs();

        System.out.println("开始生成: " + fileName);
        FreemarkerUtil.generator(fileName, param);
    }


    private static void genVueFile(String do_main, Map<String, Object> param) throws IOException, TemplateException {
        FreemarkerUtil.initConfig("vue.ftl");
        new File(vuePath).mkdirs();
        String fileName = vuePath + do_main + ".vue";
        System.out.println("开始生成: " + fileName);
        FreemarkerUtil.generator(fileName, param);
    }


    private static String extractModuleName(String generatorPath) {
        try {
            String fileName = new File(generatorPath).getName();
            return fileName.replace(".xml", "").replace("generator-config-", "");
        } catch (Exception e) {
            System.out.println("提取模块名时出错: " + e.getMessage());
            return null;
        }
    }


    /**
     * 初始化生成环境
     */
    private static void initializeGenerationEnvironment(String module, String generatorPath) {
        serverPath = serverPath.replace("[module]", module);
        new File(serverPath).mkdirs();
    }


    /**
     * 提取表信息
     */
    private static TableInfo extractTableInfo(Document document) {
        Node table = document.selectSingleNode("//table");
        Node tableName = table.selectSingleNode("@tableName");
        Node domainObjectName = table.selectSingleNode("@domainObjectName");
        System.out.println("表名: " + tableName.getText() + ", 实体类名: " + domainObjectName.getText());

        // Domain 大驼峰 JiawaTest
        String Domain = domainObjectName.getText();
        // domain 驼峰 jiawaTest
        String domain = Domain.substring(0, 1).toLowerCase() + Domain.substring(1);
        // 示例：表名 jiawa_test
        String do_main = tableName.getText().replace("_", "-");

        return new TableInfo(tableName.getText(), domainObjectName.getText(), domain, Domain, do_main);
    }


    /**
     * 配置数据库连接
     */
    private static void configureDatabaseConnection(Document document) {
        Node connectionURL = document.selectSingleNode("//@connectionURL");
        Node userId = document.selectSingleNode("//@userId");
        Node password = document.selectSingleNode("//@password");
        System.out.println("数据库URL: " + connectionURL.getText());
        DbUtil.url = connectionURL.getText();
        DbUtil.user = userId.getText();
        DbUtil.password = password.getText();
    }


    /**
     * 获取表元数据
     */
    private static TableMetadata getTableMetadata(String tableName) throws Exception {
        String tableNameCn = DbUtil.getTableComment(tableName);
        List<Field> fieldList = DbUtil.getColumnByTableName(tableName);
        Set<String> typeSet = getJavaTypes(fieldList);

        System.out.println("表中文名: " + tableNameCn);
//        System.out.println("字段数量: " + fieldList.size());

        return new TableMetadata(tableNameCn, fieldList, typeSet);
    }

    /**
     * 生成代码
     */
    private static void generateCode(TableInfo tableInfo, TableMetadata metadata, String module) throws IOException, TemplateException {
        Map<String, Object> param = buildTemplateParameters(tableInfo, metadata, module);

        genFile(tableInfo.Domain, param, "service", "service");
        if("admin".equals(targetPlatform)) {
            genFile(tableInfo.Domain, param, "controller/admin", "adminController");
        } else {
            genFile(tableInfo.Domain, param, "controller", "controller");
        }


        genFile(tableInfo.Domain, param, "req", "saveReq");
        genFile(tableInfo.Domain, param, "req", "queryReq");
        genFile(tableInfo.Domain, param, "resp", "queryResp");

        genVueFile(tableInfo.do_main, param);
    }


    /**
     * 构建模板参数
     */
    private static Map<String, Object> buildTemplateParameters(TableInfo tableInfo, TableMetadata metadata, String module) {
        Map<String, Object> param = new HashMap<>();
        param.put("domain", tableInfo.domain);
        param.put("Domain", tableInfo.Domain);
        param.put("do_main", tableInfo.do_main);
        param.put("module", module);
        param.put("fieldList", metadata.fieldList);
        param.put("tableNameCn", metadata.tableNameCn);
        param.put("typeSet", metadata.typeSet);
        param.put("readOnly", readOnly);
        param.put("targetPlatform", targetPlatform);
        return param;
    }


    private static String getGeneratorPathFromPom() {
        try {
            SAXReader saxReader = new SAXReader();
            Document document = saxReader.read(new File(pomPath));

            // 创建命名空间映射
            Map<String, String> namespaceUris = new HashMap<>();
            namespaceUris.put("pom", "http://maven.apache.org/POM/4.0.0");
            namespaceUris.put("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
            // 创建XPath并设置命名空间
            XPath xpath = document.createXPath("//pom:plugin[pom:artifactId='mybatis-generator-maven-plugin']//pom:configurationFile");
            xpath.setNamespaceURIs(namespaceUris);

            Node node = xpath.selectSingleNode(document);

            if (node != null) {
                String generatorPath = node.getText().trim();
                // 获取resources里面mybatis-generator-maven-plugin的配置文件
                String projectBaseDir = System.getProperty("user.dir");
                String generateModulePath = projectBaseDir + "/generate";
                // 拼接generator完整路径
                return generatorPath.replace("${project.basedir}", generateModulePath);
            }


        } catch (Exception e) {
            System.err.println("解析pom.xml时出错: " + e.getMessage());
        }
        return null;
    }


    /**
     * 获取所有java类型, set去重
     */

    private static Set<String> getJavaTypes(List<Field> fieldList) {
        Set<String> javaTypes = new HashSet<>();
        for (Field field : fieldList) {
            javaTypes.add(field.getJavaType());
        }
        return javaTypes;
    }


    /**
     * 表信息类
     */
    private static class TableInfo {
        final String tableName;
        final String domainObjectName;
        final String domain;
        final String Domain;
        final String do_main;

        TableInfo(String tableName, String domainObjectName, String domain, String Domain, String do_main) {
            this.tableName = tableName;
            this.domainObjectName = domainObjectName;
            this.domain = domain;
            this.Domain = Domain;
            this.do_main = do_main;
        }
    }

    /**
     * 表元数据类
     */
    private static class TableMetadata {
        final String tableNameCn;
        final List<Field> fieldList;
        final Set<String> typeSet;

        TableMetadata(String tableNameCn, List<Field> fieldList, Set<String> typeSet) {
            this.tableNameCn = tableNameCn;
            this.fieldList = fieldList;
            this.typeSet = typeSet;
        }
    }
}

